package com.liuqi.openai.tool.webhook;

import com.alibaba.fastjson.JSONObject;
import com.liuqi.openai.core.chat.Tool;
import com.liuqi.openai.model.input.PromptTemplate;
import com.liuqi.openai.tool.AbstractCustomTool;
import com.liuqi.openai.tool.ToolExecuteException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import lombok.Builder;
import lombok.extern.slf4j.Slf4j;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.config.ConnectionConfig;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.HttpStatus;
import org.apache.hc.core5.http.io.SocketConfig;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.apache.hc.core5.util.Timeout;

import static com.liuqi.openai.util.ValidationUtil.ensureNotNull;

/**
 * @author liuqi
 * @date 2025/7/20
 **/
@Slf4j
public class WebHookTool extends AbstractCustomTool<String> {

    private final static CloseableHttpClient httpClient;
    static {
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        connectionManager.setDefaultConnectionConfig(
                ConnectionConfig.custom()
                        .setConnectTimeout(Timeout.ofSeconds(60))
                        .setSocketTimeout(Timeout.ofSeconds(180))
                        .build()
        );
        connectionManager.setDefaultSocketConfig(
                SocketConfig.custom()
                        .setSoKeepAlive(true)
                        .build()
        );
        connectionManager.setMaxTotal(100);
        connectionManager.setDefaultMaxPerRoute(20);

        // 初始化 httpclient
        httpClient = HttpClients.custom()
                .setConnectionManager(connectionManager)
                .build();

        log.info("[WebHookTool], 初始化[HttpClient5], ConnectTimeout[{}]s, SocketTimeout[{}]s, MaxTotal[{}], DefaultMaxPerRoute[{}]",
                60, 180, 100, 20);
    }

    private final WebHook webHook;

    @Builder
    public WebHookTool(String toolName,
                       Tool chatTool,
                       WebHook webHook) {
        super(toolName, chatTool);
        this.webHook = ensureNotNull(webHook, "webHook");
    }

    @Override
    public String execute(String parameters, Map<String, Object> variables) throws ToolExecuteException {
        try {
            if (log.isDebugEnabled()) {
                log.debug("WebHookTool execute, url: {}, path: {}, parameters: {}, variables: {}",
                        webHook.server(), webHook.getPath(), parameters, variables);
            }

            String url = webHook.server();
            HttpPost httpPost = new HttpPost(url + webHook.getPath());
            // 解析请求头中的变量, 并赋值
            webHook.getHeaders().forEach((key, value) -> httpPost.addHeader(key, PromptTemplate.from(value).parse(variables).text()));

            if (log.isDebugEnabled()) {
                log.debug("WebHookTool execute Headers: " + JSONObject.toJSONString(httpPost.getHeaders()));
            }

            // body入参
            httpPost.setEntity(new StringEntity(parameters,
                    ContentType.create(webHook.getContentType(), StandardCharsets.UTF_8)));

            // 发起请求并获取响应结果
            String result = httpClient.execute(httpPost, response -> {
                String resp = EntityUtils.toString(response.getEntity());
                if (response.getCode() != HttpStatus.SC_OK) {
                    log.error("WebHookTool execute failed, response the http status not 200, " +
                            "httpStatus: {}, response: {}", response.getCode(), resp);
                    return resp;
                }
                return resp;
            });

            if (log.isDebugEnabled()) {
                log.debug("WebHookTool execute, url: {}, path: {}, parameters: {}, variables: {}, result: {}",
                        webHook.server(), webHook.getPath(), parameters, variables, result);
            }

            return result;
        } catch (Throwable t) {
            log.error("WebHookTool execute error.", t);
            return buildError(500, t.getMessage());
        }
    }

    private String buildError(Integer status, String errorMessage) {
        return "{\n" +
                "        \"status\": " + status + ",\n" +
                "        \"message\": \"" + errorMessage + "\"\n" +
                "    }";
    }

}
